﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TfsExtensions.Build.Controls;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Globalization;
using System.IO;
using TfsExtensions.Build.Activities.Entities;

namespace TfsExtensions.Build.Controls
{
    public partial class DialogAssemblyMetadataEditor : Form
    {
        public AssemblySettings Details { get; set; }
        public string TfsServerName { get; set; }
        public VersionControlServer TfsVersionControlServer { get; set; }
        public ICommonStructureService TfsCommonStructureService { get; set; }

        public DialogAssemblyMetadataEditor()
        {
            InitializeComponent();
            this.EnableDisableButton();
        }

        /// <summary>
        /// Handles the Click event of the btnOk control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnOk_Click(object sender, EventArgs e)
        {
            this.errorProvider.Clear();
            var isFormValidated = this.ValidateForm();
            if (isFormValidated)
            {
                var assemblyInfo = new AssemblySettings();
                var version = new AssemblyVersionSettings();
                var fileVersion = new AssemblyFileVersionSettings();
                version.IsAssemblyVersionSelected = this.chkBoxVersioning.Checked;
                if (version.IsAssemblyVersionSelected)
                {
                    version.Major = this.txtMajorVersion.Text;
                    version.Minor = this.txtMinorVersion.Text;
                    version.Build = this.txtBuildNumber.Text;
                    version.Revision = this.txtRevision.Text;

                    if (!string.IsNullOrEmpty(this.txtFileMajor.Text))
                    {
                        fileVersion.Major = this.txtFileMajor.Text;
                    }

                    if (!string.IsNullOrEmpty(this.txtFileMinor.Text))
                    {
                        fileVersion.Minor = this.txtFileMinor.Text;
                    }

                    assemblyInfo.Version = version.ToString();
                    assemblyInfo.FileVersion = fileVersion.ToString();
                }

                assemblyInfo.AssemblyVersionDetails = version;
                assemblyInfo.FileVersionDetails = fileVersion;

                var assemblySign = new AssemblySigningSettings();
                assemblySign.IsAssemblySigning = this.chkBoxSigning.Checked;
                assemblySign.IsDelaySigned = this.chkBoxDelaySign.Checked;
                if (assemblySign.IsAssemblySigning || assemblySign.IsDelaySigned)
                {
                    var keyFileName = this.txtKeyFileName.Text;
                    var keyName = this.txtKeyName.Text;
                    if (!string.IsNullOrEmpty(keyFileName))
                    {
                        assemblySign.StrongKeyFilePath = keyFileName;
                        if (File.Exists(keyFileName))
                        {
                            assemblySign.SignKeyContent = File.ReadAllBytes(keyFileName);
                        }
                    }

                    if(!string.IsNullOrEmpty(keyName))
                    {
                        assemblySign.StrongKeyName = keyName;
                    }

                    assemblyInfo.IsSigningEnabled = "Enabled";
                }

                assemblyInfo.AssemblySigningDetails = assemblySign;
                assemblyInfo.SigningDetails = assemblySign.ToString();

                var assemblyMetadata = new AssemblyApplicationSettings();
                assemblyMetadata.IsAssemblyMetadataSelected = this.chkBoxMetadata.Checked;
                if (assemblyMetadata.IsAssemblyMetadataSelected)
                {
                    assemblyMetadata.ApplicationName = this.txtApplicationName.Text;
                    assemblyMetadata.ApplicationDescription = this.txtApplicationDescription.Text;
                    assemblyMetadata.CompanyName = this.txtCompanyName.Text;
                    assemblyInfo.IsMetadataEnabled = "Enabled";
                }

                assemblyInfo.AssemblyMetadataDetails = assemblyMetadata;
                assemblyInfo.MetadataDetails = assemblyMetadata.ToString();

                assemblyInfo.FilterPath = this.txtFilterPath.Text;
                this.Details = assemblyInfo;
            }
            else
            {
                this.Details = null;
                this.DialogResult = DialogResult.None;
            }
        }

        private void chkBoxVersioning_CheckedChanged(object sender, System.EventArgs e)
        {
            var isSelected = this.chkBoxVersioning.Checked;

            this.txtMajorVersion.Enabled = isSelected;
            this.txtMinorVersion.Enabled = isSelected;
            this.txtBuildNumber.Enabled = isSelected;
            this.txtRevision.Enabled = isSelected;
            this.txtFileMajor.Enabled = isSelected;
            this.txtFileMinor.Enabled = isSelected;

            this.txtMajorVersion.Text = string.Empty;
            this.txtMinorVersion.Text = string.Empty;
            this.txtBuildNumber.Text = string.Empty;
            this.txtRevision.Text = string.Empty;
            this.txtFileMajor.Text = string.Empty;
            this.txtFileMinor.Text = string.Empty;

            if (!isSelected)
            {
                this.errorProvider.Clear();
                this.ValidateForm();
            }

            this.EnableDisableButton();
        }

        private void chkBoxMetadata_CheckedChanged(object sender, System.EventArgs e)
        {
            var isSelected = this.chkBoxMetadata.Checked;
            this.txtApplicationDescription.Text = string.Empty;
            this.txtApplicationName.Text = string.Empty;
            this.txtCompanyName.Text = string.Empty;
            this.txtApplicationName.Enabled = isSelected;
            this.txtApplicationDescription.Enabled = isSelected;
            this.txtCompanyName.Enabled = isSelected;
            if (!isSelected)
            {
                this.errorProvider.Clear();
                this.ValidateForm();
            }

            this.EnableDisableButton();
        }

        private void chkBoxSigning_CheckedChanged(object sender, System.EventArgs e)
        {
            var isSelected = this.chkBoxSigning.Checked;
            this.btnBrowse.Enabled = isSelected;
            this.txtKeyName.Enabled = isSelected;

            if (!isSelected)
            {
                this.txtKeyFileName.Text = string.Empty;
                this.txtKeyName.Text = string.Empty;
                this.errorProvider.Clear();
                this.ValidateForm();
            }

            this.EnableDisableButton();
        }

        private void chkBoxDelaySign_CheckedChanged(object sender, EventArgs e)
        {
            var isSelected = this.chkBoxDelaySign.Checked;
            this.btnBrowse.Enabled = isSelected;
            this.txtKeyName.Enabled = isSelected;

            if (!isSelected && !this.chkBoxSigning.Checked)
            {
                this.txtKeyFileName.Text = string.Empty;
                this.txtKeyName.Text = string.Empty;
                this.errorProvider.Clear();
                this.ValidateForm();
            }

            if (this.chkBoxSigning.Checked)
            {
                this.txtKeyName.Enabled = true;
            }

            this.EnableDisableButton();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            if (signFileOpenDialog.ShowDialog() == DialogResult.OK)
            {
                this.txtKeyFileName.Text = signFileOpenDialog.FileName;
            }
        }

        private void btnBrowseFolder_Click(object sender, EventArgs e)
        {
            this.UseWaitCursor = true;
            try
            {
                using (DialogBrowseServerFolder frmBrowse = new DialogBrowseServerFolder())
                {
                    frmBrowse.SelectedPath = this.txtFilterPath.Text;
                    frmBrowse.TfsVersionControlServer = this.TfsVersionControlServer;
                    frmBrowse.TfsCommonStructureService = this.TfsCommonStructureService;
                    frmBrowse.TfsServerName = this.TfsServerName;
                    frmBrowse.ShowDialog();
                    if (frmBrowse.DialogResult == DialogResult.OK)
                    {
                        this.txtFilterPath.Text = frmBrowse.SelectedPath;
                    }
                }
            }
            catch
            {

            }
            finally
            {
                this.UseWaitCursor = false;
            }
        }

        private bool ValidateForm()
        {
            var result = true;

            if (chkBoxVersioning.Checked)
            {
                result = this.ValidateAssemblyVersionNumbers();
            }

            if (string.IsNullOrEmpty(this.txtFilterPath.Text.Trim()))
            {
                errorProvider.SetError(this.btnBrowseFolder, "Please enter filter path");
                result = false;
            }

            if (chkBoxSigning.Checked)
            {
                if (string.IsNullOrEmpty(this.txtKeyFileName.Text.Trim()) && string.IsNullOrEmpty(this.txtKeyName.Text.Trim()))
                {
                    errorProvider.SetError(this.txtKeyName, "Please enter either Key file name of key container name.");
                    result = false;
                }

                if (!string.IsNullOrEmpty(this.txtKeyFileName.Text.Trim()) && !string.IsNullOrEmpty(this.txtKeyName.Text.Trim()))
                {
                    errorProvider.SetError(this.txtKeyName, "Please enter either Key file name of key container name but not both.");
                    result = false;
                }
            }

            if (this.chkBoxMetadata.Checked)
            {
                if (string.IsNullOrEmpty(this.txtCompanyName.Text.Trim()))
                {
                    errorProvider.SetError(this.txtCompanyName, "Company name cannot be left blank");
                    result = false;
                }

                if (string.IsNullOrEmpty(this.txtApplicationName.Text.Trim()))
                {
                    errorProvider.SetError(this.txtApplicationName, "Application name cannot be blank");
                    result = false;
                }

                if (string.IsNullOrEmpty(this.txtApplicationDescription.Text.Trim()))
                {
                    errorProvider.SetError(this.txtApplicationDescription, "Application description cannot be blank");
                    result = false;
                }
            }

            return result;
        }

        /// <summary>
        /// Validate all revision numbers
        /// </summary>
        /// <returns>true, if the function succeeds , else false.</returns>
        private bool ValidateAssemblyVersionNumbers()
        {
            bool isValidAssemblyMinorVersion = this.ValidateVersionNumberTextBox(this.txtMajorVersion);
            bool isValidAssemblyMajorVersion = this.ValidateVersionNumberTextBox(this.txtMinorVersion);
            bool isValidAssemblyRevision = this.ValidateVersionNumberTextBox(this.txtRevision);
            bool isValidAssemblyServicePack = this.ValidateVersionNumberTextBox(this.txtBuildNumber);
            bool isValidFileMajorVersion = this.ValidateVersionNumberTextBox(this.txtFileMajor);
            bool isValidFileMinorVersion = this.ValidateVersionNumberTextBox(this.txtFileMinor);

            return isValidAssemblyMinorVersion &&
                    isValidAssemblyMajorVersion &&
                    isValidAssemblyRevision &&
                    isValidAssemblyServicePack &&
                    isValidFileMinorVersion &&
                    isValidFileMajorVersion;
        }

        /// <summary>
        /// Validate value of a version number text box.
        /// </summary>
        /// <param name="versionTextBox">The version text box.</param>
        /// <returns>true if the function succeeds , else false</returns>
        private bool ValidateVersionNumberTextBox(TextBox versionTextBox)
        {
            bool result = true;
            try
            {
                if (versionTextBox != null)
                {
                    if (string.IsNullOrEmpty(versionTextBox.Text.Trim()))
                    {
                        result = false;
                    }
                    else
                    {
                        if (this.IsValidUnsignedInt16Value(versionTextBox.Text))
                        {
                            result = true;
                        }
                        else
                        {
                            result = false;
                        }
                    }
                }
            }
            catch
            {
                result = false;
            }
            finally
            {
                if (!result)
                {
                    var strError = string.Format(
                                                "Please provide integer value between 0 and {0}", 
                                                (UInt16.MaxValue - 1).ToString(CultureInfo.InvariantCulture));
                    errorProvider.SetError(versionTextBox, strError);
                }
            }

            return result;
        }

        /// <summary>
        /// Check if the value is a valid positive integer.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The is valid uint 16 value.</returns>
        public bool IsValidUnsignedInt16Value(string value)
        {
            bool result = false;
            try
            {
                if (value != null)
                {
                    int item = int.Parse(value, CultureInfo.InvariantCulture);
                    if ((item <= (65535 - 1)) && (item >= 0))
                    {
                        result = true;
                    }
                }
            }
            catch
            {
                result = false;
            }

            return result;
        }

        /// <summary>
        /// Enables the disable button.
        /// </summary>
        private void EnableDisableButton()
        {
            if (this.chkBoxMetadata.Checked || this.chkBoxSigning.Checked || this.chkBoxVersioning.Checked)
            {
                this.btnOk.Enabled = true;
                return;
            }

            this.btnOk.Enabled = false;
        }
    }
}
